﻿/**
 *  Lab19 is a space wehere I put AS3 classes I write for me, developing my works.
 * 	I hope they could be helpful for other peoples. I believe I can improve the code sharing it.
 * 
 *  This file is part of lab19.
 *  
 *  lab19 is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License. 
 *  lab19 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.  
 *   You should have received a copy of the GNU General Public License along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
 * @author Copyright (C) 2007 officinanessuno
 * @version 0.1
*/

package lab19.utility{
	
	import flash.events.EventDispatcher;
	import flash.geom.ColorTransform;
	import flash.utils.Dictionary;
	
	import fl.transitions.Tween;
	import fl.transitions.TweenEvent;
	import fl.transitions.easing.*;
	
	import core.events.TweenManagerEvent;
	
	/**
	 * @eventType core.events.TweenManagerEvent.MOTION_CHANGE
	 */
	[Event(name="tweenChange", type="core.events.TweenManagerEvent")]

	/**
	 * @eventType core.events.TweenManagerEvent.MOTION_FINISH
	 */
	[Event(name="tweenFinish", type="core.events.TweenManagerEvent")]
	
	/**
	manage tweens.
	each transtion is identifed by an id, a target object and two objects containing start and finish sets of key/value couples.<br/>You can even change color property using word "color" as key and its hex value as value.<br/>If alpha property goes to 0 the object is made unvisible
	
	@see core.events.TweenManagerEvent
	*/
	dynamic public class TweenManager extends EventDispatcher{
		
		private var _tweens:Dictionary;
		
		public function TweenManager(){
			 _tweens = new Dictionary()
		}
		
/////////////////PUBLIC METHODS
		
		/**
		 * if the transitions 'id' already exists this method stops it.<br/>set the new finish object and starts the tween
		 * @param	univoque id of the tween
		 * @param	target object which key properties refer
		 * @param	nextVal finish set of key/value properties
		 * @param	duration the duration of the transition
		 * @param	mod the easing mode function
		 */
		public function change(id:String, target:Object, nextVal:Object, duration:Number=1, mod:Function=null):void{
			//se esiste la stoppo
			if(_tweens[id]){
				if(_tweens[id].isPlaying) _tweens[id].stop();
			//altrimenti al acreo	
			}else{
				_initTween(target, id);
			}

			//recupero tween eoggetto di questo change
			var tw:Tween = _tweens[id] as Tween;
			var ob:Object = _tweens[tw];

			tw.func = (mod!=null) ? mod : None.easeNone;
			tw.duration = duration;
			
			ob.prevVal = new Object();
			ob.nextVal = new Object();
			
			for (var s:String in nextVal){
				
				if((ob.target[s]!=null)||(s=="color")){
					switch(s){
						
						case "color":
							ob.prevVal[s] = ob.target.transform.colorTransform;
							var ct:ColorTransform = new ColorTransform();
							ct.color = nextVal[s];
							ob.nextVal[s] = ct;
							break;
						
						case "alpha":
							ob.prevVal[s] = ob.target[s];
							ob.nextVal[s] = nextVal[s];
							ob.target.visible = ob.target.visible||(Number(nextVal[s])>0);
							break;		
							
						default:
							ob.prevVal[s] = ob.target[s];
							ob.nextVal[s] = nextVal[s];
					}
				}
			}
			
			tw.start();
		}
		/**
		 * stops the tween identified by id
		 * @param	univoque id of the tween
		 */
		public function stop(id:String):void{
			if(_tweens[id]){
				if(_tweens[id].isPlaying) _tweens[id].stop();
			}
		}
/////////////////PRIVATE METHODS

		/**
		 * create an object with id, prevVal, nextVal and target propereties<br/>add the listeners<br/>associate this object to the tween in the dictionary<br/>associate the tween to its id in the dictionary
		 * @param	target target object
		 * @param	id univoque id of the tween
		 */
		private function _initTween(target:Object, id:String):void{
			var myObj:Object = new Object();
			myObj.id = id;
			myObj.twPos = 0;
			myObj.target = target;
			myObj.prevVal = new Object();
			myObj.nextVal = new Object();
			
			var tween:Tween = new Tween(myObj, "twPos", None.easeNone, 0, 1, .1, true);
			tween.stop();
			tween.addEventListener(TweenEvent.MOTION_CHANGE, _tweenChange);
			tween.addEventListener(TweenEvent.MOTION_FINISH, _tweenFinish);
			_tweens[tween] = myObj;
			_tweens[id] = tween;
		}

		/**
		 * catch the tweenChange event, add more info e redisptach it as TweenManagerEvent
		 * @param	the tween Event
		 */
		private function _tweenChange(e:TweenEvent):void{
			var tw:Tween = e.currentTarget as Tween;
			var ob:Object = _tweens[tw];
			for (var s:String in ob.nextVal){
				switch(s){
					case "color":
						ob.target.transform.colorTransform = _changeColor(ob.prevVal[s], ob.nextVal[s], tw.position);
						break;
					default:
						ob.target[s] = ob.prevVal[s] + (ob.nextVal[s]-ob.prevVal[s])*tw.position;
				}
			}
			dispatchEvent(new TweenManagerEvent(TweenManagerEvent.MOTION_CHANGE, {tween:tw, info:ob}));
		}
		
		/**
		 * catch the tweenFinish event, add more info e redisptach it as TweenManagerEvent
		 * @param	the tween Event
		 */
		private function _tweenFinish(e:TweenEvent):void{
			var tw:Tween = e.currentTarget as Tween;
			var ob:Object = _tweens[tw];
			
			for (var s:String in ob.nextVal){
				switch(s){
					case "color":
						ob.target.transform.colorTransform = ob.nextVal[s];
						break;
					case "alpha":
						ob.target[s] = ob.nextVal[s];
						ob.target.visible = Boolean(ob.target[s]); 
						break;	
					default:
						ob.target[s] = ob.nextVal[s];
				}
			}
			dispatchEvent(new TweenManagerEvent(TweenManagerEvent.MOTION_FINISH, {tween:tw, info:ob}));
		}	
		
		/**
		 * used on motionChange steps to change the color
		 * @param	s start colorTransform
		 * @param	e end colorTransform
		 * @param	now the point between 0 and 1 where the tween is
		 * @return
		 */
		private function _changeColor(s:ColorTransform, e:ColorTransform, now:Number):ColorTransform{
			var ctRes:ColorTransform = new ColorTransform();

			ctRes.redOffset = s.redOffset + (e.redOffset-s.redOffset)*now;
			ctRes.greenOffset = s.greenOffset + (e.greenOffset-s.greenOffset)*now;
			ctRes.blueOffset = s.blueOffset + (e.blueOffset-s.blueOffset)*now;

			ctRes.redMultiplier = ctRes.greenMultiplier = ctRes.blueMultiplier = 0;
			
			return ctRes;
		}
	}
}
